﻿package com.dg.gaming.api.common{
	import com.dg.gaming.api.common.msg.*;
	import com.ericfeminella.collections.ArrayList;
	import com.ericfeminella.collections.HashMap;
	import nanoxml.XMLElement;

	/**
	 * ...
	 * @author 
	 */
	public class TableList extends Observable implements ITransmittable {

		/**
		 * HashMap containing a number of Table objects.  They key is an Integer
		 * object of the table number.
		 */
		protected var tablelist:HashMap;


		/**
		 * A vector of unused table numbers.
		 */


		/**
		 * The highest #'d table that is either in use or in the unusedTableNumber
		 * vector.
		 */


		/**
		 * Default constructor which sets up a brand new TableList object with no
		 * Tables in its HashMap.
		 */
		public function TableList(message:XMLElement=null) {
			// Create new hash map for tables
			tablelist=new HashMap  ;
			if (message!=null) {
				if (message.name!=Msg.TABLE_LIST) {
					throw new TransmissionException("Error parsing table list");
				}

				// Create new table from string and add to Hash
				var e:ArrayList=ArrayList.createArrayList(message.chileds);
				var n:int=e.length;
				for (var i:int=0; i<n; i++) {
					var childElement:XMLElement=XMLElement(e[i]);
					if (childElement.name==Msg.TABLE) {
						var table:Table=new Table  ;
						table.initXML(childElement);
						tablelist.put(table.getTableNum(),table);
					}
				}


			}

		}


		/**
		 * Add a new Table object to the HashMap.  The Table object is created using
		 * the parameters creator, isPublic and a computed table number which is
		 * generated using the computeNewTableNum() method.  This Table object is
		 * then stored in a HashMap with this computed table number (Integer) as its
		 * key.
		 *
		 * @param creator     The user that is creating this table.
		 * @param isPublic    True / false if public / private table.
		 * @param properties  Properties of this table.
		 * @return            The new table.
		 */
		public function addTable(creator:User,isPublic:Boolean):Table {
			// Generate new table number.
			var newTableNum:Number=1;

			// Create new Table object.
			var table:Table=new Table  ;
			table.init(newTableNum+"",creator,isPublic);

			// Store in HashMap using the table number as its key.
			tablelist.put(newTableNum+"",table);

			// Notify listeners
			setChanged();
			notifyObservers("+T "+newTableNum);

			// Return the table number
			return table;
		}

		/**
		 * Add a new Table object to the HashMap.  The Table object is created using
		 * the parameters creator, isPublic and a computed table number which is
		 * generated using the computeNewTableNum() method.  This Table object is
		 * then stored in a HashMap with this computed table number (Integer) as its
		 * key.
		 *
		 * @param creator     The user that is creating this table.
		 * @param isPublic    True / false if public / private table.
		 * @param properties  Properties of this table.
		 * @return            The new table.
		 */
		public function addTableObj(tbl:Table):void {
			// Generate new table number.

			tablelist.put(tbl.getTableNum(),tbl);

			// Notify listeners
			setChanged();
			notifyObservers("+T "+tbl.getTableNum());

		}

		/**
		 * Remove table from the list.  This is usually called when all the users
		 * leave a particular table for example.
		 *
		 * @param tableNum  Number of the table to be removed.
		 */
		public function removeTable(tableNum:String):void {
			var iTableNum:Number=parseInt(tableNum);
			tablelist.remove(iTableNum);

			// Notify listeners
			setChanged();
			notifyObservers("-T "+tableNum);
		}

		/**
		 * Remove a player from a table.  If the player is the last player to
		 * leave the table then the table will also be removed from the HashMap.
		 *
		 * @param tableNum  Table number.
		 * @param player    The name of the player to remove.
		 * @return true if the player was removed succesfully.
		 */
		public function removePlayer(tableNum:String,player:Number):Boolean {
			var table:Table=getTable(tableNum);

			// Verify that table & player exist
			if (table==null||player==-1) {
				return false;
			}

			// Verify that the player is removed from the player list.
			var players:PlayerList=table.getPlayerList();
			if (! players.removePlayer(player)) {
				return false;
			}

			// See if the table is now empty, and if so, remove it.
			if (players.size()==0) {
				removeTable(tableNum);
			}

			// Notify listeners
			setChanged();
			notifyObservers("-P "+tableNum+" "+player);

			return true;
		}

		/**
		 * Remove a user from tables.
		 *
		 * @param player
		 */
		public function removeUserFromTables(player:Number):void {
			var keys:ArrayList=ArrayList.createArrayList(tablelist.getKeys());

			// Loop through each table and remove the player
			for (var i:int=0; i<keys.length; i++) {
				var tableNum:String=keys[i];
				removePlayer(tableNum,player);
			}

			// Notify listeners
			setChanged();
			notifyObservers("-U "+player);
		}

		/**
		 * Return a Table object from a specified table number.
		 *
		 * @param tableNum   Table number.
		 * @return           Table object if exists.
		 */
		public function getTable(tableNum:String):Table {
			return Table(tablelist.getValue(tableNum));
		}

		/**
		 * Returns a list of all the table numbers.
		 *
		 * @return   Array of integer table numbers.
		 */
		public function getTablesNumbers():Array {
			var keys:Array=ArrayList.createArrayList(tablelist.getKeys());

			return keys;
		}

		/**
		 * Update a table in the table list.
		 *
		 * @param tableNum
		 * @param table
		 */
		public function updateTable(tableNum:String,table:Table):void {
			var tableCount:int=tablelist.size();
			tablelist.put(tableNum,table);

			var notify:String="";
			if (tablelist.size()>tableCount) {
				notify="+T "+tableNum;
			}

			// Notify listeners
			setChanged();
			notifyObservers(notify);
		}

		/**
		 * Return the size of the table list.
		 *
		 * @return   Number of Table objects in TableList.
		 */
		public function size():int {
			return tablelist.size();
		}

		/**
		 * Return a list of table numbers of a user.
		 *
		 * @param username
		 * @return
		 */
		public function getTableNumsForUser(username:Number):Array {

			var tableNums:Array=getTablesNumbers();
			var userTableNumsTemp:Array=new ArrayList(tableNums.length);

			var c:int=0;
			for (var i:int=0; i<tableNums.length; i++) {
				var table:Table=getTable(tableNums[i]);
				if (table.containsPlayer(username)) {
					userTableNumsTemp[c++]=tableNums[i];
				}
			}

			// Create new integer array with populated values
			var userTableNums:Array=new ArrayList(c);
			for (var j:int=0; j<c; j++) {
				userTableNums[j]=userTableNumsTemp[j];
			}
			return userTableNums;
		}

		/**
		 * Return the number of tables that a specified user has created
		 * i.e. that the user is the owner of.
		 *
		 * @param username   Username to check.
		 * @return           Number of tables this user is owner of.
		 */
		public function getNumOfTablesUserOwns(userid:Number):int {
			var tableNums:Array=getTablesNumbers();

			var count:int=0;
			for (var i:int=0; i<tableNums.length; i++) {
				var table:Table=getTable(tableNums[i]);
				if (table.getOwner()==userid) {
					count++;
				}
			}

			return count;
		}

		/**
		 * Flatten the current list of tables in use.
		 *
		 * @see com.dg.gaming.api.common.msg.ITransmittable#flatten()
		 */
		public function flatten():XMLElement {
			var message:XMLElement=new XMLElement  ;
			message.name=Msg.TABLE_LIST;

			var tableNums:Array=getTablesNumbers();
			for (var i:int=0; i<tableNums.length; i++) {
				var table:Table=getTable(tableNums[i]);
				message.addChild(table.flatten());
			}

			return message;
		}

		/**
		 * Refresh observers - calls the setChanged() and notifyObservers ()
		 * methods in the Observable class.
		 */
		public function refreshObservers():void {
			setChanged();
			notifyObservers();// notify any class which observes this class
		}
	}
}